package net.cachedb4j.service.impl;

import java.io.IOException;
import java.io.Serializable;

import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.util.Assert;

import net.cachedb4j.service.CacheService;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Element;
import net.spy.memcached.AddrUtil;
import net.spy.memcached.MemcachedClient;

public class CacheServiceImpl implements CacheService {

	private org.apache.commons.logging.Log logger = LogFactory.getLog(getClass());

	private Cache localCache;

	private String cacheServerList;

	String cacheServerWeights;

	private boolean cacheCluster = false;
	
	private boolean enable = false;

	private MemcachedClient mc;

	public CacheServiceImpl() {
		
	}

	public void init() {
		if (this.cacheCluster) {
			try {
				mc = new MemcachedClient(AddrUtil.getAddresses(cacheServerList));
			} catch (IOException e) {
				logger.error("failed to initialize memcached pool");
			}
			logger.info("memcached pool initialized.");
		}
	}

	public void shutdown() {
		if (this.cacheCluster) {
			mc.shutdown();
		}
	}

	public void setCacheServerList(String cacheServerList) {
		this.cacheServerList = cacheServerList;
	}

	public void setCacheServerWeights(String cacheServerWeights) {
		this.cacheServerWeights = cacheServerWeights;
	}

	public void setCacheCluster(boolean cacheCluster) {
		this.cacheCluster = cacheCluster;
	}

	public void setEnable(boolean enable) {
		this.enable = enable;
	}

	public void setLocalCache(Cache localCache) {
		this.localCache = localCache;
	}

	public void incr(String key, int factor, int startingValue) {
		mc.incr(key, factor, startingValue);
	}

	public void set(String key, int cacheTimeSeconds, Object obj) {
		if(enable) {
			Assert.hasText(key);
			Assert.notNull(obj);
			Assert.notNull(localCache);
			if (this.cacheCluster) {
				mc.set(key, cacheTimeSeconds == 0 ? 3600 : cacheTimeSeconds, obj);
			} else {
				Element element = new Element(key, (Serializable) obj);
				localCache.put(element);
			}
		}
	}

	public void delete(String key) {
		if(enable) {
			Assert.hasText(key);
			Assert.notNull(localCache);
			if (this.cacheCluster) {
				mc.delete(key);
			} else {
				localCache.remove(key);
			}
		}
	}

	public Object get(String key) {
		if(enable) {
			Assert.hasText(key);
			Assert.notNull(localCache);
			Object rt = null;
			if (this.cacheCluster) {
				rt = mc.get(key);
			} else {
				Element element = null;
				try {
					element = localCache.get(key);
				} catch (CacheException cacheException) {
					throw new DataRetrievalFailureException("Cache failure: "
							+ cacheException.getMessage());
				}
				if (element != null)
					rt = element.getValue();
			}
			return rt;
		}
		return null;
	}

}
